package com.candy.biz.manager;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import com.candy.biz.domain.entity.SysDept;
import com.candy.biz.domain.entity.SysUser;
import com.candy.biz.domain.param.SysDeptSaveParam;
import com.candy.biz.domain.vo.SysDeptVO;
import com.candy.biz.domain.vo.SysUserVO;
import com.candy.biz.mapper.SysDeptMapper;
import com.candy.common.domain.PageVO;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.PostConstruct;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;



/**
 * 部门-通用处理层。
 *
 * @author rong xi
 * @date 2023/09/18 09:18
 * @version 1.0.0
 */
@Component
@AllArgsConstructor
@Slf4j
public class SysDeptManager {

    private final SysDeptMapper sysDeptMapper;
    private static SysDeptManager manager;

    @PostConstruct
    private void init(){
        manager = this;
    }


    /**
     * 部门po对象转部门vo对象
     *
     * @param po po对象
     * @return vo对象
     */
    public static SysDeptVO poToVo(SysDept po){
        SysDeptVO convert = CommonManager.convert(po, SysDeptVO.class);
        convert.setParentName(SysDeptManager.getDept(convert.getParentId()).map(SysDept::getDeptName).orElse(""));
        return convert;
    }

    /**
     * 部门分页对象转换分页视图数据
     *
     * @param page 分页结果
     * @return 分页数据
     */
    public static PageVO<SysDeptVO> pageToPageVO(Page<SysDept> page) {
        return PageVO.of(posToVos(page.getRecords()),page.getTotalRow());
    }

    /**
     * 部门po集合转部门vo集合
     *
     * @param pos po集合对象
     * @return vos vo集合对象
     */
    public static List<SysDeptVO> posToVos(List<SysDept> pos){
        List<SysDeptVO> convert = CommonManager.convert(pos, SysDeptVO.class);
        List<Long> parentIds = pos.stream().map(SysDept::getParentId).collect(Collectors.toList());
        Optional<Map<Long, SysDept>> sysDeptMapOpt = SysDeptManager.getDeptMap(parentIds);
        for (SysDeptVO sysDeptVO : convert) {
            sysDeptVO.setParentName(sysDeptMapOpt.map(m->m.get(sysDeptVO.getParentId())).map(SysDept::getDeptName).orElse(""));
        }
        return convert;
    }


    /**
     * 部门po集合转部门树vo集合
     *
     * @param pos po集合对象
     * @return vos 树vo集合对象
     */
    public static List<Tree<Long>> posToTreeList(List<SysDept> pos,Long rootId){
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定义排序名 都要默认值的
        treeNodeConfig.setIdKey("id");
        treeNodeConfig.setWeightKey("orderNum");
        treeNodeConfig.setNameKey("deptName");
        treeNodeConfig.setParentIdKey("parentId");
        // 最大递归深度
        treeNodeConfig.setDeep(5);
        //转换器 (含义:找出父节点为字符串零的所有子节点, 并递归查找对应的子节点, 深度最多为 5)
        List<Tree<Long>> treeList = TreeUtil.build(pos, rootId, treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setWeight(treeNode.getOrderNum());
                    tree.setId(treeNode.getId());
                    tree.setName(treeNode.getDeptName());
                    tree.setParentId(treeNode.getParentId());
                    tree.putExtra("orderNum", treeNode.getOrderNum());
                    tree.putExtra("delFlag", treeNode.getDelFlag());
                    tree.putExtra("remark", treeNode.getRemark());
                    tree.putExtra("createUser", treeNode.getCreateUser());
                    tree.putExtra("createTime", treeNode.getCreateTime());
                    tree.putExtra("updateUser", treeNode.getUpdateUser());
                    tree.putExtra("updateTime", treeNode.getUpdateTime());
                });
        return Optional.ofNullable(treeList).orElseGet(Collections::emptyList);
    }

    /**
     * 部门po集合转部门树vo集合
     *
     * @param pos po集合对象
     * @return vos 树vo集合对象
     */
    public static Tree<Long> posToTree(List<SysDept> pos,Long rootId){
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定义排序名 都要默认值的
        treeNodeConfig.setWeightKey("orderNum");
        treeNodeConfig.setNameKey("title");
        // 最大递归深度
        treeNodeConfig.setDeep(5);
        //转换器 (含义:找出父节点为字符串零的所有子节点, 并递归查找对应的子节点, 深度最多为 5)
        Tree<Long> rootTree = TreeUtil.buildSingle(pos, rootId, treeNodeConfig,
                 (treeNode, tree) -> {
                    tree.setWeight(treeNode.getOrderNum());
                    tree.setId(treeNode.getId());
                    tree.setName(treeNode.getDeptName());
                    tree.setParentId(treeNode.getParentId());
                    tree.putExtra("spread", true);
        });
        rootTree.setName("顶级");
        rootTree.putExtra("spread", true);
        return rootTree;
    }


    /**
     * 新增部门准备
     *
     * @param param 新增参数
     * @return po对象
     */
    public static SysDept insertPrepare(SysDeptSaveParam param){
        SysDept sysDept = BeanUtil.copyProperties(param, SysDept.class);
        sysDept.setId(IdUtil.getSnowflakeNextId());
        sysDept.setCreateUser(StpUtil.getLoginIdAsLong());
        sysDept.setCreateTime(LocalDateTime.now());
        return sysDept;
    }

    /**
     * 修改部门准备
     *
     * @param param 修改参数
     * @return po对象
     */
    public static SysDept updatePrepare(SysDeptSaveParam param){
        SysDept sysDept = BeanUtil.copyProperties(param, SysDept.class);
        sysDept.setUpdateUser(StpUtil.getLoginIdAsLong());
        sysDept.setUpdateTime(LocalDateTime.now());
        return sysDept;
    }

    /**
     * 获取部门map
     *
     * @return 部门map
     */
    public static Optional<Map<Long,SysDept>> getDeptMap(List<Long> deptIds){
        return Optional.ofNullable(deptIds)
                .filter(CollectionUtil::isNotEmpty)
                .map(i->manager.sysDeptMapper.selectListByIds(i).stream().collect(Collectors.toMap(SysDept::getId, Function.identity())));
    }

    /**
     * 获取部门map
     *
     * @return 部门map
     */
    public static Optional<SysDept> getDept(@NotNull Long deptId){
        return Optional.ofNullable(manager.sysDeptMapper.selectOneById(deptId));
    }

}
